package com.nervenets.general.jwt.aspect;

import com.google.common.collect.Lists;
import com.nervenets.general.Global;
import com.nervenets.general.config.ApplicationProperties;
import com.nervenets.general.enumeration.Platform;
import com.nervenets.general.exception.LogicException;
import com.nervenets.general.exception.TokenIllegalException;
import com.nervenets.general.jwt.util.JwtUtils;
import com.nervenets.general.model.SecurityUser;
import com.nervenets.general.utils.HttpTools;
import com.nervenets.general.utils.SpringContextHolder;
import com.nervenets.general.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;

import static com.nervenets.general.Global.TokenIllegalType.NONE_USER;
import static com.nervenets.general.i18n.I18nTranslator.braceTranslate;
import static com.nervenets.general.i18n.I18nTranslator.translate;

/**
 * 方法体权限验证
 */
@Component
@Aspect
@Slf4j
public class JwtSecurityAspect {

    /**
     * 返回通知
     */
    @Before("@annotation(com.nervenets.general.jwt.aspect.JwtSecurity) && @annotation(jwtSecurity)")
    public void doBefore(JoinPoint joinPoint, JwtSecurity jwtSecurity) {
        final Platform platform = Platform.customValueOf(Objects.requireNonNull(HttpTools.getHttpRequest()).getHeader(Global.Constants.PLATFORM_KEY));
        ApplicationProperties applicationProperties = SpringContextHolder.getBean(ApplicationProperties.class);

        //读取全局需要鉴权的终端
        List<Platform> checkPlatforms = Arrays.asList(applicationProperties.getAuthorizePlatforms());
        //如果方法体自定义终端，则以方法体自定义为准
        if (jwtSecurity.platforms().length > 0) {
            checkPlatforms = Lists.newArrayList(jwtSecurity.platforms());
        }

        if (jwtSecurity.required() && checkPlatforms.contains(platform)) {
            Class<?> cls = joinPoint.getSourceLocation().getWithinType();
            SecurityUser securityUser = JwtUtils.getUser();
            if (null == securityUser)
                throw new TokenIllegalException(translate("application.login.expired") + "-none user aspect", NONE_USER);

            if (cls.isAnnotationPresent(JwtRole.class)) {
                JwtRole role = cls.getAnnotation(JwtRole.class);

                String menuPermission = String.format("%s:%s", role.group(), role.function());
                if (!securityUser.getPermissions().contains(menuPermission)) {
                    throw new LogicException(403, String.format(translate("application.permission.dismiss"), braceTranslate(role.groupName()), braceTranslate(role.functionName())));
                }

                if (applicationProperties.isOpenFunctionRole()) {
                    if (!StringUtils.isBlank(jwtSecurity.permission())) {
                        String permission = String.format("%s:%s:%s", role.group(), role.function(), jwtSecurity.permission());

                        if (!securityUser.getPermissions().contains(permission)) {
                            throw new LogicException(403, String.format(translate("application.permission.dismiss"), braceTranslate(role.functionName()), braceTranslate(jwtSecurity.permissionName())));
                        }
                    }
                }
            }
        }
    }
}
